package servier

import (
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/winc-link/hummingbird-modbus-rtu/config"
	"github.com/winc-link/hummingbird-sdk-go/service"
	"net"
	"sync"
	"time"

	"github.com/goburrow/modbus"
)

// 配置常量

// 寄存器地址配置
const (
	TempRegister     = 0x0000
	HumidityRegister = 0x0001
	NumRegisters     = 2
)

type DTUConnection struct {
	ID         string
	Conn       net.Conn
	Handler    *modbus.TCPClientHandler
	Client     modbus.Client
	LastActive time.Time
	mu         sync.Mutex
	IsActive   bool
	RetryCount int
}

type SensorData struct {
	DeviceID    string
	Temperature float32
	Humidity    float32
	Timestamp   time.Time
	Success     bool
	Error       string
}

type ModbusServer struct {
	listener    net.Listener // 修正为正确的net.Listener类型
	connections sync.Map
	connPool    chan struct{}
	shutdown    chan struct{}
	dataChan    chan SensorData
	workerPool  chan struct{}
	ctx         context.Context
	cancel      context.CancelFunc
	wg          sync.WaitGroup

	cfg    *config.BaseConfig
	driver *service.DriverService
}

func NewModbusServer(cfg *config.BaseConfig, dr *service.DriverService) *ModbusServer {
	ctx, cancel := context.WithCancel(context.Background())
	return &ModbusServer{
		connections: sync.Map{},
		connPool:    make(chan struct{}, cfg.MaxConnections),
		shutdown:    make(chan struct{}),
		dataChan:    make(chan SensorData, cfg.DataChannelBuffer),
		workerPool:  make(chan struct{}, cfg.WorkerPoolSize),
		ctx:         ctx,
		cancel:      cancel,
		cfg:         cfg,
		driver:      dr,
	}
}

func (s *ModbusServer) Start() error {
	listener, err := net.Listen("tcp", ":502")
	if err != nil {
		return err
	}
	s.listener = listener

	go s.acceptConnections()
	return nil
}

func (s *ModbusServer) acceptConnections() {
	for {
		select {
		case <-s.ctx.Done():
			return
		case s.connPool <- struct{}{}:
			conn, err := s.listener.Accept()
			if err != nil {
				<-s.connPool
				if ne, ok := err.(net.Error); ok && ne.Temporary() {
					s.driver.GetLogger().Info("临时错误: %v, 重试中...", err)
					time.Sleep(100 * time.Millisecond)
					continue
				}
				s.driver.GetLogger().Errorf("接受连接错误: %v", err)
				return
			}

			s.wg.Add(1)
			go s.handleNewConnection(conn)
		}
	}
}

func (s *ModbusServer) handleNewConnection(conn net.Conn) {
	defer func() {
		conn.Close()
		<-s.connPool
		s.wg.Done()
	}()

	connID := conn.RemoteAddr().String()
	s.driver.GetLogger().Info("新的DTU连接: %s", connID)

	handler := modbus.NewTCPClientHandler(connID)
	handler.Timeout = time.Duration(s.cfg.RequestTimeout) * time.Millisecond
	//handler.SlaveId = 1

	if err := handler.Connect(); err != nil {
		s.driver.GetLogger().Errorf("连接 %s 创建Modbus处理器失败: %v", connID, err)
		return
	}
	defer handler.Close()

	dtuConn := &DTUConnection{
		ID:         connID,
		Conn:       conn,
		Handler:    handler,
		Client:     modbus.NewClient(handler),
		LastActive: time.Now(),
		IsActive:   true,
	}

	s.connections.Store(connID, dtuConn)
	defer s.connections.Delete(connID)

	s.wg.Add(1)
	go s.dataCollectionLoop(dtuConn)

	heartbeatTicker := time.NewTicker(time.Duration(s.cfg.HeartbeatInterval) * time.Second)
	defer heartbeatTicker.Stop()

	for dtuConn.IsActive {
		select {
		case <-s.ctx.Done():
			dtuConn.IsActive = false
			return
		case <-heartbeatTicker.C:
			if err := s.checkHeartbeat(dtuConn); err != nil {
				s.driver.GetLogger().Errorf("心跳检测失败 %s: %v", connID, err)
				dtuConn.IsActive = false
				return
			}
		}
	}
}

func (s *ModbusServer) dataCollectionLoop(conn *DTUConnection) {
	defer s.wg.Done()

	ticker := time.NewTicker(time.Duration(s.cfg.DataChannelBuffer) * time.Second)
	defer ticker.Stop()

	for conn.IsActive {
		select {
		case <-s.ctx.Done():
			conn.IsActive = false
			return
		case <-ticker.C:
			data := s.collectSensorData(conn)

			select {
			case s.dataChan <- data:
			case <-time.After(100 * time.Millisecond):
				s.driver.GetLogger().Infof("数据通道已满，丢弃数据: %s", conn.ID)
			}
		}
	}
}

func (s *ModbusServer) collectSensorData(conn *DTUConnection) SensorData {
	data := SensorData{
		DeviceID:  conn.ID,
		Timestamp: time.Now(),
	}

	conn.mu.Lock()
	defer conn.mu.Unlock()

	results, err := conn.Client.ReadHoldingRegisters(TempRegister, NumRegisters)
	if err != nil {
		data.Error = fmt.Sprintf("读取寄存器失败: %v", err)
		data.Success = false
		conn.RetryCount++

		if conn.RetryCount > s.cfg.MaxRetryAttempts {
			conn.IsActive = false
			data.Error = "超过最大重试次数，连接关闭"
		}
		return data
	}

	conn.RetryCount = 0
	conn.LastActive = time.Now()

	if len(results) >= 4 {
		tempRaw := int16(binary.BigEndian.Uint16(results[0:2]))
		humRaw := int16(binary.BigEndian.Uint16(results[2:4]))
		data.Temperature = float32(tempRaw) / 10.0
		data.Humidity = float32(humRaw) / 10.0
		data.Success = true
	} else {
		data.Success = false
		data.Error = "无效的数据长度"
	}

	return data
}

func (s *ModbusServer) checkHeartbeat(conn *DTUConnection) error {
	conn.mu.Lock()
	defer conn.mu.Unlock()

	if time.Since(conn.LastActive) > 2*time.Duration(s.cfg.HeartbeatInterval) {
		return errors.New("连接不活跃时间过长")
	}

	_, err := conn.Client.ReadHoldingRegisters(0x0000, 1)
	if err != nil {
		conn.RetryCount++
		if conn.RetryCount > s.cfg.MaxRetryAttempts {
			return errors.New("超过最大心跳重试次数")
		}
		return err
	}

	conn.RetryCount = 0
	conn.LastActive = time.Now()
	return nil
}

func (s *ModbusServer) StartDataWorkers(numWorkers int) {
	for i := 0; i < numWorkers; i++ {
		go func(workerID int) {
			for data := range s.dataChan {
				s.processData(workerID, data)
			}
		}(i)
	}
}

func (s *ModbusServer) processData(workerID int, data SensorData) {
	s.workerPool <- struct{}{}
	defer func() { <-s.workerPool }()

	if data.Success {
		s.driver.GetLogger().Infof("Worker %d 处理数据 - 设备: %s, 温度: %.1f°C, 湿度: %.1f%%, 时间: %v",
			workerID, data.DeviceID, data.Temperature, data.Humidity,
			data.Timestamp.Format("2006-01-02 15:04:05.000"))
	} else {
		s.driver.GetLogger().Infof("Worker %d 处理错误 - 设备: %s, 错误: %s, 时间: %v",
			workerID, data.DeviceID, data.Error,
			data.Timestamp.Format("2006-01-02 15:04:05.000"))
	}
}

func (s *ModbusServer) Stop() {
	s.cancel()
	close(s.shutdown)

	if s.listener != nil {
		s.listener.Close()
	}

	s.connections.Range(func(key, value interface{}) bool {
		conn := value.(*DTUConnection)
		conn.IsActive = false
		conn.Conn.Close()
		return true
	})

	s.wg.Wait()
	close(s.dataChan)
	s.driver.GetLogger().Info("服务器已停止")
}

func GetModbusRtuServer() *ModbusServer {
	return &ModbusServer{}
}
